#include "myopenglwidget.h"

#define LENGTH      1.0f
#define HALF_LENGTH LENGTH / 2

#define WIDTH       1.0f
#define HALF_WIDTH  WIDTH / 2

#define HEIGHT      1.0f
#define HALF_HEIGHT HEIGHT / 2

MyOpenGLWidget::MyOpenGLWidget(QWidget* parent)
    : QOpenGLWidget(parent),
      m_shaderProgram(nullptr),
      m_vbo(QOpenGLBuffer::VertexBuffer),
      m_textures{0,0,0,0,0,0},
      m_pitch(0), m_roll(0), m_yaw(0)
{
    m_vertices = {

        // Position                                 // Texture coords
        -HALF_LENGTH,  HALF_HEIGHT,  HALF_WIDTH,    1.0f, 0.0f,
        -HALF_LENGTH, -HALF_HEIGHT,  HALF_WIDTH,    1.0f, 1.0f,
         HALF_LENGTH, -HALF_HEIGHT,  HALF_WIDTH,    0.0f, 1.0f,
         HALF_LENGTH,  HALF_HEIGHT,  HALF_WIDTH,    0.0f, 0.0f,

         HALF_LENGTH,  HALF_HEIGHT,  HALF_WIDTH,    0.0f, 1.0f,
         HALF_LENGTH, -HALF_HEIGHT,  HALF_WIDTH,    1.0f, 1.0f,
         HALF_LENGTH, -HALF_HEIGHT, -HALF_WIDTH,    1.0f, 0.0f,
         HALF_LENGTH,  HALF_HEIGHT, -HALF_WIDTH,    0.0f, 0.0f,

         HALF_LENGTH,  HALF_HEIGHT, -HALF_WIDTH,    0.0f, 1.0f,
         HALF_LENGTH, -HALF_HEIGHT, -HALF_WIDTH,    0.0f, 0.0f,
        -HALF_LENGTH, -HALF_HEIGHT, -HALF_WIDTH,    1.0f, 0.0f,
        -HALF_LENGTH,  HALF_HEIGHT, -HALF_WIDTH,    1.0f, 1.0f,

        -HALF_LENGTH,  HALF_HEIGHT, -HALF_WIDTH,    0.0f, 1.0f,
        -HALF_LENGTH, -HALF_HEIGHT, -HALF_WIDTH,    0.0f, 0.0f,
        -HALF_LENGTH, -HALF_HEIGHT,  HALF_WIDTH,    1.0f, 0.0f,
        -HALF_LENGTH,  HALF_HEIGHT,  HALF_WIDTH,    1.0f, 1.0f,

        -HALF_LENGTH,  HALF_HEIGHT, -HALF_WIDTH,    0.0f, 0.0f,
        -HALF_LENGTH,  HALF_HEIGHT,  HALF_WIDTH,    0.0f, 1.0f,
         HALF_LENGTH,  HALF_HEIGHT,  HALF_WIDTH,    1.0f, 1.0f,
         HALF_LENGTH,  HALF_HEIGHT, -HALF_WIDTH,    1.0f, 0.0f,

        -HALF_LENGTH, -HALF_HEIGHT, -HALF_WIDTH,    0.0f, 1.0f,
        -HALF_LENGTH, -HALF_HEIGHT,  HALF_WIDTH,    0.0f, 0.0f,
         HALF_LENGTH, -HALF_HEIGHT,  HALF_WIDTH,    1.0f, 0.0f,
         HALF_LENGTH, -HALF_HEIGHT, -HALF_WIDTH,    1.0f, 1.0f,
    };
}

void MyOpenGLWidget::initializeGL()
{
    initializeOpenGLFunctions();

    if (!m_shaderProgram.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/model.vert")) {
        qDebug() << "ERROR:" << m_shaderProgram.log();
        return;
    }

    if (!m_shaderProgram.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/model.frag")) {
        qDebug() << "ERROR:" << m_shaderProgram.log();
        return;
    }

    if (!m_shaderProgram.link()) {
        qDebug() << "ERROR:" << m_shaderProgram.log();
        return;
    }

    m_textures[0] = new QOpenGLTexture(QImage("./images/side1.jpg"));
    m_textures[1] = new QOpenGLTexture(QImage("./images/side2.jpg"));
    m_textures[2] = new QOpenGLTexture(QImage("./images/side3.jpg"));
    m_textures[3] = new QOpenGLTexture(QImage("./images/side4.jpg"));
    m_textures[4] = new QOpenGLTexture(QImage("./images/side5.jpg"));
    m_textures[5] = new QOpenGLTexture(QImage("./images/side6.jpg"));

    QOpenGLVertexArrayObject::Binder{ &m_vao };

    m_vbo.create();
    m_vbo.bind();

    m_vbo.allocate(m_vertices.data(), m_vertices.size() * sizeof(GLfloat));

    m_shaderProgram.setAttributeBuffer(0, GL_FLOAT, 0, 3, sizeof(GLfloat) * 5);
    m_shaderProgram.enableAttributeArray(0);

    m_shaderProgram.setAttributeBuffer(1, GL_FLOAT, sizeof(GLfloat) * 3, 2, sizeof(GLfloat) * 5);
    m_shaderProgram.enableAttributeArray(1);

    glEnable(GL_DEPTH_TEST);
}

void MyOpenGLWidget::paintGL()
{
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    m_shaderProgram.bind();

    QMatrix4x4 model;
    model.perspective(40.0f, 1, 0.01f, 5.1f);
    model.translate(-0, -0, -3);
    model.rotate(m_pitch, 1.0, 0.0, 0.0);
    model.rotate(m_roll, 0.0, 0.0, 1.0);
    model.rotate(m_yaw, 0.0, 1.0, 0.0);
    m_shaderProgram.setUniformValue("model", model);

    QOpenGLVertexArrayObject::Binder{ &m_vao };

    // 绘制
    for (int i = 0; i < 6; i++) {
        m_textures[i]->bind();
        glDrawArrays(GL_TRIANGLE_FAN, i * 4, 4);
    }
}

void MyOpenGLWidget::resizeGL(int width, int height)
{
    glViewport(0, 0, width, height);
}

MyOpenGLWidget::~MyOpenGLWidget()
{
    makeCurrent();

    for (int i = 0; i < 6; i++)
        if (m_textures[i])
            delete m_textures[i];

    doneCurrent();
}
